import java.awt.image.BufferedImage;
import java.util.*;

public class IPWindow
{
	// The frame handles window events.
	public IPFrame frame;

	public ROI roi;

	public Vector<MassVis> Mass_Visuals;  //size is equal to this.roi.Mass_Vector.length

	// This is the backup image for the undo operation.
	// todo: change this into a stack of undo'able items
	public ImageData backupImage;

	public ImageApplication app;
	public int windowID;

	public ImageApplication getImageApp()
	{
		return app;
	}

	public MassVis getMassVis(int mass_id)
	{
		for (MassVis mv : Mass_Visuals)
		{
			if (mv.Mass_ID == mass_id)
			{
				return mv;
			}
		}
		return null;
	}

	public void updateFrame() { frame.repaint(); }
	public ROI getROI() { return roi; }

	public ImageData getActiveImage()
	{
		if (roi == null)
		{
			return null;
		}
		else
		{
			return roi.getOriginalImage();
		}
	}

	public boolean hasActiveImage()
	{
		return getActiveImage() != null;
	}

	/**
	 * Create window without any image loaded.
	 * This should only be called by the application.
	 */
	public IPWindow(ImageApplication _app)
	{
		app = _app;
		frame = new IPFrame(this);
		roi = null;
 		Mass_Visuals = new Vector<MassVis>();
		backupImage = null;
		frame.setVisible(true);
	}

	/**
	 * Create window using specified image and ROI
	 * This should only be called by the application.
	 */
	public IPWindow(ImageApplication _app,
			ImageData img, int x, int y, int w, int h)
	{
		app = _app;
		roi = new ROI(img, x, y, w, h);
		Mass_Visuals = new Vector<MassVis>();
		frame = new IPFrame(this);
		frame.setVisible(true);
		//frame.repaint();
		p.print("creating window with roi specified");
	}

	/**
	 * Window ID set
	 */
	public void setWindowId(int id)
	{
		windowID = id;
		frame.setTitle("ImageApp - winid: " + id);
	} 
	public int getWindowId() { return windowID; }

	/**
	 * Called when a new image is opened.
	 */
	public void loadNewImage(String filename)
	{
		roi = new ROI(filename);
		Mass_Visuals = new Vector<MassVis>();
		frame.enableSaveMenuItems(hasActiveImage());
	}

	/**
	 * Called by application to signal this window will close.
	 */
	public void notifyWindowIsClosing()
	{
		// Free image resources
		

		// Hide frame and free resources
		frame.setVisible(false);
		frame.dispose();
	}

	/**
	 * Called by frame when save is invoked.
	 */
	public void saveActiveImage(String filename)
	{
		if (hasActiveImage())
		{
			getActiveImage().saveImage(filename);
		}
		else
		{
			p.print("No image to save.");
		}
	}

	public void applyThreshold(int value)
	{
		if (hasActiveImage())
		{
			backupImage();
			app.threshold(value, this);
			frame.repaint();
		}
		else
		{
			p.print("No image to operate on.");
		}
	}

	public void applyImageNegative()
	{
		if (hasActiveImage())
		{
			backupImage();
			app.imageNegative(this);
			frame.repaint();
		}
		else
		{
			p.print("No image to operate on.");
		}
	}
	
	public void applyMedianFileter(){
		if (hasActiveImage()){
			backupImage();
			app.medianFilter(this);
			frame.repaint();
		}
	}

//	??????????????????????????????????????????????????????????????????
	//----------reena----start------
//	public void applyextract_sharpness(){
//		if (hasActiveImage()){
//			backupImage();
//			app.extract_sharpness(this);
//			frame.repaint();
//		}
//	}
//
//	public void applyextract_Thinness(){
//		if (hasActiveImage()){
//			backupImage();
//			app.extract_Thinness(this);
//			frame.repaint();
//		}
//	}
//
//	public void applyImageBoundary(){
//		if (hasActiveImage()){
//			backupImage();
//			app.ImageBoundary(this);
//			frame.repaint();
//		}
//	}
//	
//
//	//----------reena----end--------

	public void applyContrastStretch(Boolean contrastInc)
	{
		if (hasActiveImage())
		{
			backupImage();
			app.contrastStretch(contrastInc, this);
			frame.repaint();
		}
		else
		{
			p.print("No image to operate on.");
		}
	}

	/**
	 * Create new ipimage from existing one.
	 *
	 */
	public void backupImage()
	{
		backupImage = getActiveImage().clone();
	}

	public void restoreImage()
	{
		if (backupImage != null)
		{
			// Create new ipimage from existing one.
			roi = new ROI(backupImage, 0, 0,
					backupImage.getWidth(), backupImage.getHeight());
			frame.repaint();
		}
		else
		{
			p.print("No backup image found.");
		}
	}

	/**
	 * Convenience function to change activeImage. Please backupImage() first so Undo works.
	 * @param new_image
	 */
	void setActiveImage(ImageData new_image) {
		int[] new_image_pixels = new int[new_image.getWidth() * new_image.getHeight()];
		new_image.getPixels(new_image_pixels, 0, 0, new_image.getWidth(), new_image.getHeight());
		getActiveImage().setPixels(new_image_pixels, 0, 0, new_image.getWidth(), new_image.getHeight());
	}
	
	// Boni: We probably should not be setting the render image directly.
	// Otherwise, the pixel data will be out of sync.
	// TODO: Refactor this so that either:
	// 1) setting render image updates pixel data, or
	// 2) this method (or caller of this method) should set pixel data instead
	void setActiveImg(BufferedImage image){
		getActiveImage().setImageData(image);
	}



	/**method to generate the Mass_Visuals which consists of a vector
           of Mass_Vis object, one for each mass that exists in this.ROI
         */

        public void generate_Mass_Visuals(){
           this.Mass_Visuals = new Vector<MassVis>(); //initialize to empty

           Vector<Mass>  massVector = this.roi.getMasses();

           for(Mass mass : massVector) {
             MassVis m = new MassVis(mass);
             this.Mass_Visuals.add(m);
           }


	   System.out.println("generate_Mass_Visuals:  # generate" + this.Mass_Visuals.size());
	   System.out.flush();

        }
      
     ImageData colorMassPixels(int mass_ID){
    	 	int width = roi.getWidth();
        	int height = roi.getHeight();        	
        	// Get pixels
        	int[] pixels = roi.getOriginalImage().allocPixels();
        	roi.getOriginalImage().getPixels(pixels, 0, 0,width, height);
        	int[] lab_pixels = roi.getLabeledImage().allocPixels();
        	roi.getLabeledImage().getPixels(lab_pixels, 0, 0, width, height);
        	int pixel, p_grey, pixel_Red, pixel_Green, pixel_Blue;

        	// Change the color of the pixels.
        	for (int y=0; y < height; y++)	{
        		for (int x=0; x < width; x++){
        			int lab_Pixel = lab_pixels[y*width + x];
        			if (Util.getRGBavg(lab_Pixel) == mass_ID){
        				p_grey = Util.getRGBavg(pixels[y*width + x]);
        				pixel_Red = (2*p_grey + 255)/3;
        				pixel_Green = (2*p_grey + 255)/3;
        				pixel_Blue = 0;
        				pixel = pixels[y*width + x];
        				pixel = Util.setRGB(pixel_Red, pixel_Green, pixel_Blue); // apply brown color
        			}
        			else
        				pixel = pixels[y*width + x];
        			pixels[y*width + x] = pixel;
        		}
        	}
        	// Modify a copy of the image not the original
        	ImageData copyImage = new ImageData(roi.getOriginalImage(), 0, 0, width, height);
        	copyImage.setPixels(pixels, 0, 0,width, height);
        	return copyImage;
        }
}

